/*
 * serial.c
 *
 *  Created on: Aug 19, 2012
 *      Author: drew
 */



#include "serial.h"

#define GETBUFFSIZE( x )  sizeof( x )/sizeof( char )

int iSerialStringLength( char * cString )
{
  int iCount = 0;

  /* Look for end of string delimiter */
  while( *(cString++) != '\0' )
  {
    iCount++;
  }

  return iCount;
}

void * vpSerialListenerRunLoop( void * pvParameters )
{
  xpSerialDescription xpSerialPort = (xpSerialDescription)pvParameters;

  char cReadBuffer[128];

  printf( "Starting Serial Run Loop: Serial Port %d\n", xpSerialPort->ePort );

  for( ;; )
  {
    memset( cReadBuffer, '\0', GETBUFFSIZE( cReadBuffer ) );

    if( read( xpSerialPort->iSerialRefNum, cReadBuffer, GETBUFFSIZE( cReadBuffer ) ) <= 0 )
    {
      printf( "NOTE: Serial Port %d Read Error\n", xpSerialPort->ePort );
      break;
    }

    //printf("Recieved: %s", cReadBuffer );

     xpSerialPort->vpRxCallback( cReadBuffer );
  }

  return NULL;
}

xpSerialDescription xpSerialCreateObject( eSerialPort ePort, eSerialBaudRate eBaudRate, vpSerialRxCallback vpRxCallback )
{
  xpSerialDescription xpSerialObject = (xpSerialDescription)malloc( sizeof( xSerialDescription ) );

  xpSerialObject->ePort = ePort;

  switch( eBaudRate )
  {
    case SERIAL_BAUDRATE_9600:
      xpSerialObject->xBaudRate = B9600;
      break;
    case SERIAL_BAUDRATE_19200:
      xpSerialObject->xBaudRate = B19200;
      break;
    case SERIAL_BAUDRATE_38400:
      xpSerialObject->xBaudRate = B38400;
      break;
    case SERIAL_BAUDRATE_115200:
      xpSerialObject->xBaudRate = B115200;
      break;
    default:
      break;
  }

  xpSerialObject->vpRxCallback = vpRxCallback;

  return xpSerialObject;
}

void vSerialDestroyObject( xpSerialDescription xpSerialPort )
{
  free( xpSerialPort );
}

int iSerialInitialize( xpSerialDescription xpSerialPort )
{
  char cFileString[64], cRxFileString[64], cTxFileString[64];
  FILE * fpRxSerialFile, * fpTxSerialFile;

  /*
   * Initialize pin mux for serial port
   */

  switch( xpSerialPort->ePort )
  {
    case SERIAL_PORT_1:

      if( ( fpRxSerialFile = fopen( "/sys/kernel/debug/omap_mux/uart1_rxd", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 1 RX\n" );
        return 1;
      }

      sprintf( cRxFileString, "%d", 20 );

      if( ( fpTxSerialFile = fopen( "/sys/kernel/debug/omap_mux/uart1_txd", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 1 TX\n" );
        return 1;
      }

      sprintf( cTxFileString, "%d", 0 );

      break;
    case SERIAL_PORT_2:

      if( ( fpRxSerialFile = fopen( "/sys/kernel/debug/omap_mux/spi0_sclk", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 2 RX\n" );
        return 1;
      }

      sprintf( cRxFileString, "%d", 21 );

      if( ( fpTxSerialFile = fopen( "/sys/kernel/debug/omap_mux/spi0_d0", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 2 TX\n" );
        return 1;
      }

      sprintf( cTxFileString, "%d", 1 );

      break;
    case SERIAL_PORT_3:

      if( ( fpTxSerialFile = fopen( "/sys/kernel/debug/omap_mux/ecap_in_pwm0_out", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 3 TX\n" );
        return 1;
      }

      sprintf( cTxFileString, "%d", 1 );

      break;
    case SERIAL_PORT_4:

      if( ( fpRxSerialFile = fopen( "/sys/kernel/debug/omap_mux/gpmc_wait0", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 4 RX\n" );
        return 1;
      }

      sprintf( cRxFileString, "%d", 26 );

      if( ( fpTxSerialFile = fopen( "/sys/kernel/debug/omap_mux/gpmc_wpn", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 4 TX\n" );
        return 1;
      }

      sprintf( cTxFileString, "%d", 6 );

      break;
    case SERIAL_PORT_5:

      if( ( fpRxSerialFile = fopen( "/sys/kernel/debug/omap_mux/lcd_data9", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 5 RX\n" );
        return 1;
      }

      sprintf( cRxFileString, "%d", 24 );

      if( ( fpTxSerialFile = fopen( "/sys/kernel/debug/omap_mux/lcd_data8", "rb+" ) ) == NULL )
      {
        printf( "ERROR: Cannot configure UART 5 TX\n" );
        return 1;
      }

      sprintf( cTxFileString, "%d", 4 );

      break;
    default:
      break;
  }

  fwrite( cRxFileString, sizeof( char ), iSerialStringLength( cRxFileString ), fpRxSerialFile );
  fclose( fpRxSerialFile );

  if( SERIAL_PORT_3 != xpSerialPort->ePort )
  {
    fwrite( cTxFileString, sizeof( char ), iSerialStringLength( cTxFileString ), fpTxSerialFile );
    fclose( fpTxSerialFile );
  }

  /*
   * Initialize the serial port settings
   * */
  sprintf( cFileString, "/dev/ttyO%d", xpSerialPort->ePort );

  if( ( xpSerialPort->iSerialRefNum = open( cFileString, O_RDWR | O_NOCTTY | O_NDELAY ) ) == -1 )
  {
    printf( "ERROR: Cannot open Serial Port %d\n", xpSerialPort->ePort );
    return 1;
  }

  fcntl( xpSerialPort->iSerialRefNum, F_SETFL, 0 );

  tcgetattr( xpSerialPort->iSerialRefNum, &xpSerialPort->xSettings );

  xpSerialPort->xSettings.c_cflag = xpSerialPort->xBaudRate | CS8 | CREAD | CLOCAL | HUPCL;

  cfsetospeed( &xpSerialPort->xSettings, xpSerialPort->xBaudRate );
  cfsetispeed( &xpSerialPort->xSettings, xpSerialPort->xBaudRate );

  tcsetattr( xpSerialPort->iSerialRefNum, TCSANOW, &xpSerialPort->xSettings );

  if( pthread_create( &xpSerialPort->xThreadHandle, NULL, vpSerialListenerRunLoop, (void*)xpSerialPort ) )
  {
    printf( "ERROR: Could not spawn thread for Serial Port %d\n", xpSerialPort->ePort );
    return 1;
  }

  return 1;
}

void iSerialCleanup( xpSerialDescription xpSerialPort )
{
  close( xpSerialPort->iSerialRefNum );
}

int iSerialPrint( xpSerialDescription xpSerialPort, char * cpBuff, int iLength )
{
  int iBytesSent;

  if( ( iBytesSent = write( xpSerialPort->iSerialRefNum, cpBuff, iLength ) ) != iLength )
  {
    printf( "ERROR: Write not successful Serial Port %d\n", xpSerialPort->ePort );
  }

  return iBytesSent;
}

int iSerialStartListenerRunLoop( xpSerialDescription xpSerialPort )
{

  if( pthread_create( &xpSerialPort->xThreadHandle, NULL, vpSerialListenerRunLoop, (void*)xpSerialPort ) )
  {
    printf( "ERROR: Could not spawn thread for Serial Port %d\n", xpSerialPort->ePort );
    return 1;
  }

  return 0;
}
